from datetime import timedelta, datetime
from typing import Optional

from fastapi import HTTPException, status, Depends
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt

SECRET_KEY = "ed970259a19edfedf1010199c7002d183bd15bcaec612481b29bac1cb83d8137"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='http://127.0.0.1:8089/mgrUser/mgrLogin')


class TokenUtil:

    @staticmethod
    def create_jwt_token(user_id: str, expire_delta: Optional[timedelta] = None):
        data = {'user_id': user_id}
        # 如果传入了过期时间, 那么就是用该时间, 否则使用默认的时间
        expire = datetime.utcnow() + expire_delta if expire_delta else datetime.utcnow() + timedelta(
            minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        # 需要加密的数据data必须为一个字典类型, 在数据中添加过期时间键值对, 键exp的名称是固定写法
        data.update({'exp': expire})
        # 进行jwt加密
        token = jwt.encode(claims=data, key=SECRET_KEY, algorithm=ALGORITHM)
        return token

    @staticmethod
    def checkToke(token: str = Depends(oauth2_scheme)):
        # 定义一个验证异常的返回
        credentials_exception = HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="认证失败",
            # 根据OAuth2规范, 认证失败需要在响应头中添加如下键值对
            headers={'WWW-Authenticate': "Bearer"}
        )
        # 验证token
        try:
            # 解密token, 返回被加密的字典
            payload = jwt.decode(token=token, key=SECRET_KEY, algorithms=[ALGORITHM])
            print(f'payload: {payload}')
            # 从字典中获取user_id数据
            user_id = payload.get('user_id')
            print(f'user_id: {user_id}')
            # 若没有user_id, 则返回认证异常
            if not user_id:
                raise credentials_exception
        except JWTError as e:
            print(f'认证异常: {e}')
            # 如果解密过程出现异常, 则返回认证异常
            raise credentials_exception
        # 解密成功, 返回token中包含的user_id
        return user_id
